<?php

/*
 * This is the notcat class, a framework for wordpress that make the developer's 
 * life easier.
 * 
 * By Javier Marquez (javi@marquex.es) 04-10-2011
 */
if(!class_exists('NotCAT')){
class NotCAT {
   private $tpl_order;
   private $tpl_ext = '.php';
   private $debug = false;
   private $is_404 = false;
   private $post_tpls = array();
   private $comment_tpls = array();
   private $post_tpl_hierarchy = array('author', 'meta', 'category', 'tag', 'taxonomy');
   function __construct() {
        require_once('const.php');
    }
    
    /**
     * Load a miscelaneous file from the parts/misc folder.
     * @param String $filename The name (without extension) of the filename to include
     */
    public function misc($filename){
        $path = locate_template("parts/misc/$filename.php");
        if($this->debug)
           $this->printo("Including: " . $path);
        include $path;
    }
    
    
    /**
     * Loads the meta file from parts/metas folder. If no filename is provided, it loads a file depending on the context of the query.
     * @param String $filename Optional. The name of the file, without extension, to be loaded.
     */
    public function get_meta($filename = ''){
	do_action( 'get_meta', $filename );
        $this->get_part('parts/metas/meta-', $filename);
    }
    
    /**
     * Loads the meta file from headers/header folder. If no filename is provided, it loads a file depending on the context of the query.
     * @param String $filename Optional. The name of the file, without extension, to be loaded.
     */
    public function get_header($filename = ''){
	do_action( 'get_header', $filename );
        $this->get_part('parts/headers/header-', $filename);
    }
    
    
    /**
     * Loads the meta file from parts/footers folder. If no filename is provided, it loads a file depending on the context of the query.
     * @param String $filename Optional. The name of the file, without extension, to be loaded.
     */
    public function get_footer($filename = ''){
	do_action( 'get_footer', $filename );
        $this->get_part('parts/footers/footer-', $filename);
    }
    
    public function get_loop($filename = ''){
	do_action( 'get_loop', $filename );
        $this->get_part('parts/loops/loop-', $filename);
    }
    
    public function get_content($filename = ''){
		do_action( 'get_content', $filename );
	        //In twentyeleven the content is called as a template part so let's call
	        //its action too for compatibility
		do_action( 'get_template_part_content', 'content', get_post_format() );
		
		$tpl_order = $this->tpl_order;
		if(!empty($this->post_tpls))
			$tpl_order = $this->get_post_tpl_order();
		
	    $this->get_part('parts/contents/content-', $filename, $tpl_order);
    }
    
    /**
     * Retrieves the misc/searchform.php file. Notcat hooks this function to the
     * get_search_form filter, so, for compatibility, the best way of calling it
     * is calling the wp_function get_search_form(), this way all the get_seach_forms
     * actions and filters are also called.
     * @param String $form The default wordpress form
     * @return String If the file is found it returns an empty string. Otherwise it returns the original form. 
     */
    public function get_searchform($form){
        if(!empty($form)){ //This check is necessary to not call this function twice. See bug http://core.trac.wordpress.org/ticket/19321
            $path = locate_template("parts/misc/searchform.php");
            if($this->debug)
               $this->printo("Including: " . $path);

            if ( '' != $path ) {
                    require($path);
                    return;
            }
            //If the file doesn't exists we return the wp default search form
            return $form;
        }
    }
    
    public function select_template(){
        //restore the actual value of 404
        global $wp_query;
        $wp_query->is_404 = $this->is_404;
        
        $path =  $this->get_part_path('tpls/tpl-', $this->tpl_order);
        
        if($this->debug)
           $this->printo("Including: " . $path);
        
        return $path;        
    }
    
    private function get_part($prefix, $filename, $tpl_order = null){
        $path = '';
        if(null == $tpl_order)
        	$tpl_order = $this->tpl_order;
        if(empty($filename))
            $path = $this->get_part_path($prefix, $tpl_order);
        else
            $path = locate_template($prefix . $filename . $this->tpl_ext);
       
       if($this->debug)
           $this->printo("Including: " . $path);
       
       include $path;
    }
    
    private function get_part_path($prefix, $order){            
        $i = 0;
        while($i<sizeof($order)){
            if($filename = locate_template($prefix . $order[$i++] . $this->tpl_ext)){
                return $filename;
            }
        }
        if(!$found)
            return locate_template($prefix . 'default' . $this->tpl_ext);
    }
    
    public function set_tpl_order(){
    	$this->tpl_order = $this->current_element_tpl_order();
    }
    
    public function current_element_tpl_order(){
        global $wp_query;
        global $post;
        //We need to hook into 404 template filter so let's make the request be
        //a 404
        $queried_object = get_queried_object();
        $this->is_404 = $wp_query->is_404;
        $wp_query->is_404 = true;
        
        
        //Start creating the array
        $order = array();
        if(is_front_page())
            $order[] = 'front-page';
        if(is_home())
            $order[] = 'home';
        if($this->is_404)
            $order[] = '404';
        elseif(is_singular()){
            //pages can have a custom template assigned
            if(is_page()){
                $template = get_post_meta($id, '_wp_page_template', true);
                if ( !empty($template) && $template != 'default'&& !validate_file($template) ){
                    $order[] = $template;
                }
            }
            //particular templates
            $ptype = $queried_object->post_type;
            $order[] = 'single-' . $ptype . '-' . $post->post_name;
            $order[] = 'single-' . $ptype . '-' . $post->ID;
            //attachments by types
            if(is_attachment()){
                global $posts;
                $type = explode('/', $posts[0]->post_mime_type);
                $order[] = "$type[0]_$type[1]";
                $order[] = "$type[0]";
            }
            //general single templates
            $order[] = 'single-' . $ptype;
            $order[] = $ptype;
            $order[] = 'single';
        }
        elseif(is_archive()){
            if(is_category()){
                $order[] = 'category-' . $queried_object->slug;
                $order[] = 'category-' . $queried_object->term_id;
                $order[] = 'category';
                $order[] = get_post_type();
            }
            elseif(is_post_type_archive()){
                $order[] =  'archive-' . get_post_type();
                $order[] = get_post_type();
            }
            elseif(is_tag()){
                $order[] = 'tag-' . $queried_object->slug;
                $order[] = 'tag-' . $queried_object->term_id;
                $order[] = 'tag';
                $order[] = get_post_type();
            }
            elseif(is_author()){
                $order[] = 'author-' . $queried_object->user_nicename;
                $order[] = 'author-' . $queried_object->ID;
                $order[] = 'author';
            }
            elseif(is_date()){
                $order[] = 'date';
            }
            elseif(is_search()){
                $order[] = 'search';
            }
            elseif(is_tax()){
                $taxonomy = $queried_object->taxonomy;

                $order[] = "taxonomy-$taxonomy-{$queried_object->slug}.php";
                $order[] = "taxonomy-$taxonomy.php";
                $order[] = 'taxonomy.php';
                $order[] = get_post_type();
            }
            $order[] = 'archive';
        }
        elseif(is_comments_popup())
            $order[] = 'comments-popup';
        
        //$order[] ='default'; //This is appended in get_part()
        $this->tpl_order = $order;
    }
    
    public function debug($d = true){
        $this->debug = $d;
        return $this;
    }
    
    private function printo($message){
        echo '<div class="notcatdebug">', $message, '</div>';
    }
    
    public function add_post_tpl($newtpls = ''){
    	if(empty($this->post_tpls)){
    		$this->post_tpls = array(
    			'meta' => array(),
    			'author' => array(),
    			'tag' => array(),
    			'category' => array(),
    			'taxonomy' => array()
    		);
    	}
    	if(is_array($newtpls)){
    		foreach($newtpls as $tpl){
    			$this->add_single_post_tpl($tpl);
    		}
    	}
    	elseif(!empty($newtpls)){
    		$this->add_single_post_tpl($newtpls);
    	}
    	elseif($this->debug)
    		$this->printo("add_post_tpl function is called but no tpl was given.");
    	return $this;
    }
    
    private function add_single_post_tpl($tpl){
    	$tplparts = explode('-', $tpl);
    	
    	if(in_array($tplparts[0], array('meta', 'taxonomy')) && sizeof($tplparts)>3)
    		$this->post_tpls[$tplparts[0]][] = array($tplparts[1], implode('-', array_slice($tplparts, 2)));
    	else
    		$this->post_tpls[$tplparts[0]][] = implode('-', array_slice($tplparts, 1));
    }
    
    private function get_post_tpl_order(){
    	global $post;
    	$post_templates = array();
    	$hierarchy = apply_filters('post_tpl_hierarchy', $this->post_tpl_hierarchy);
    	foreach($hierarchy as $type){
    		if($type == 'author'){
    			foreach($this->post_tpl['author'] as $author){
    				global $authordata;
    				if($author == $authordata->ID || $author == $authordata->nicename)
    					$post_templates[] = 'author-'.$author;
    			}
    		}
    		elseif($type == 'meta'){
    			foreach($this->post_tpl['meta'] as $meta){
    				if(get_post_meta($post->ID, $meta[0], true) == $meta[1])
    					$post_templates[] = 'meta-'.$meta[0].'-'.$meta[1];
    			}
    		}
    		elseif($type == 'category'){
    			foreach($this->post_tpl['category'] as $cat){
    				if(has_cagetegory($cat))
    					$post_templates[] = 'category-'.$cat;
    			}
    		}
    		elseif($type == 'tag'){
    			foreach($this->post_tpl['tag'] as $tag){
    				if(has_tag($tag))
    					$post_templates[] = 'tag-'.$tag;
    			}
    		}
    		elseif($type == 'taxonomy'){
    			foreach($this->post_tpl['taxonomy'] as $tax){
    				if(has_term($tax[1], $tax[0]))
    					$post_templates[] = 'taxonomy-'.$tax[0].'-'.$tax[1];
    				
    			}
    		}
    	}
    	return array_merge($post_templates, $this->current_element_tpl_order());
    }
    
}
global $notcat;
$notcat = new NotCAT;

add_action('template_redirect',array($notcat, 'set_tpl_order'),1000);//Here we built the array with the selectable templates
add_filter('404_template', array($notcat, 'select_template'),1000);//Here we choose the correct template
add_filter('get_search_form', array($notcat, 'get_searchform'),1);//Modify the searchform path to parts/misc/searchform.php
}
